package org.ucas.faker.web.utils.mql.domain;

import org.ucas.faker.web.utils.model.Documentable;

import java.util.LinkedList;

public class Where implements Cloneable {

  protected CONN conn;
  protected Float boost;
  private LinkedList<Where> wheres = new LinkedList<>();

  public Where(String connStr) {
    this.conn = CONN.valueOf(connStr.toUpperCase());
  }

  public Where(CONN conn) {
    this.conn = conn;
  }

  public static Where newInstance() {
    return new Where(CONN.AND);
  }

  public void addWhere(Where where) {
    wheres.add(where);
  }

  public CONN getConn() {
    return this.conn;
  }

  public void setConn(CONN conn) {
    this.conn = conn;
  }

  public LinkedList<Where> getWheres() {
    return wheres;
  }

  public Float getBoost() {
    return boost;
  }

  public void setBoost(Float boost) {
    this.boost = boost;
  }

  public float genScore(Documentable document) {
    float res = 0.0f;
    for (Where where : wheres) {
      if (conn == CONN.AND) {
        float subScore = where.genScore(document);
        if (subScore == 0) return 0;
        res = Math.max(res, subScore);
      } else if (conn == CONN.OR) {
        float subScore = where.genScore(document);
        res = Math.max(res, subScore);
      } else if (conn == CONN.NOT)
        res = where.notScore(document);
    }
    return res;
  }

  public float notScore(Documentable document) {
    float res = 0.0f;
    for (Where where : wheres) {
      if (conn == CONN.AND) {
        float subScore = where.notScore(document);
        res = Math.max(res, subScore);
      } else if (conn == CONN.OR) {
        float subScore = where.notScore(document);
        if (subScore == 0) return 0;
        res = Math.max(subScore, res);
      } else if (conn == CONN.NOT)
        res = where.genScore(document);
    }
    return res;
  }

  @Override
  public String toString() {
    if (wheres.size() > 0) {
      String whereStr = wheres.toString();
      return this.conn + " ( " + whereStr.substring(1, whereStr.length() - 1) + " ) ";
    } else {
      return "";
    }

  }

  @Override
  public Object clone() throws CloneNotSupportedException {
    Where clonedWhere = new Where(this.getConn());
    for (Where innerWhere : this.getWheres()) {
      clonedWhere.addWhere((Where) innerWhere.clone());
    }
    return clonedWhere;
  }

  public enum CONN {
    AND, OR, NOT;

    public CONN negative() {
      return this == AND ? OR : AND;
    }
  }

}

